#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time : 2024/10/9 9:25
# @Author : 沈复
# @Email : 1259577135
# @File : common_util.py
# @Desc :



from fastapi import FastAPI, HTTPException, Request, status
from fastapi.responses import HTMLResponse, JSONResponse
from fastapi.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles
from pymongo import MongoClient
from bson import ObjectId
from typing import Dict, Optional
import uvicorn
from urllib.parse import urlparse

app = FastAPI()
templates = Jinja2Templates(directory="templates")  # 加载模板目录
app.mount("/static", StaticFiles(directory="static"), name="static")  # 挂载静态文件

class MongoDBView:
    def __init__(self, mongo_uri: str):
        """
        初始化 MongoDB 视图类
        :param mongo_uri: MongoDB 连接字符串（包含数据库名称）
        """
        # 解析连接字符串，提取数据库名称
        parsed_uri = urlparse(mongo_uri)
        self.db_name = parsed_uri.path.strip('/')  # 提取数据库名称
        if not self.db_name:
            raise ValueError("Database name is missing in the MongoDB URI.")

        # 初始化 MongoDB 客户端
        self.client = MongoClient(mongo_uri)
        self.db = self.client[self.db_name]
        self.registered_tables = {}  # 存储已注册的表信息
        self.first_table = None  # 记录第一个注册的表
        self.system_title = "管理系统"  # 默认系统标题

    def set_system_title(self, title: str):
        """
        设置系统标题
        :param title: 系统标题
        """
        self.system_title = title

    def get_field_names(self, table_name):
        """
        获取集合的字段名
        :param table_name: 集合名称
        :return: 字段名列表
        """
        collection = self.db[table_name]
        sample = collection.find_one()
        if sample:
            return list(sample.keys())
        else:
            return []

    def register_table(
        self,
        table_name: str,
        table_alias: Optional[str] = None,
        field_aliases: Optional[Dict[str, str]] = None,
    ):
        """
        动态注册表的路由
        :param table_name: 表名（MongoDB 集合名称）
        :param table_alias: 表别名（用于页面显示）
        :param field_aliases: 字段别名（用于页面显示）
        """
        if table_name in self.registered_tables:
            raise ValueError(f"Table '{table_name}' is already registered.")

        # 获取字段名
        fields = self.get_field_names(table_name)

        # 生成字段别名
        if field_aliases is None:
            field_aliases = {field: field.capitalize() for field in fields}

        # 存储表信息
        self.registered_tables[table_name] = {
            "table_alias": table_alias or table_name,  # 如果未指定表别名，则使用表名
            "field_aliases": field_aliases,  # 字段别名
        }

        # 记录第一个注册的表
        if not self.first_table:
            self.first_table = table_name

        # 注册路由
        self._register_html_page(table_name)  # 注册 HTML 页面路由
        self._register_crud_api(table_name)   # 注册 API 路由

    def _register_crud_api(self, table_name: str):
        """
        注册增删改查 API
        """
        @app.get(f"/{table_name}/api", response_model=dict)
        async def get_all(page: int = 1, limit: int = 10):
            # 查询分页数据
            collection = self.db[table_name]
            skip = (page - 1) * limit
            data = list(collection.find({}).skip(skip).limit(limit))
            total = collection.count_documents({})

            # 将 _id 转换为字符串
            for item in data:
                item["_id"] = str(item["_id"])

            return {
                "data": data,
                "total": total,
                "page": page,
                "limit": limit,
            }

        @app.get(f"/{table_name}/api/{{item_id}}", response_model=dict)
        async def get_one(item_id: str):
            # 查询单条数据
            collection = self.db[table_name]
            try:
                # 尝试将 item_id 转换为 ObjectId
                query = {"_id": ObjectId(item_id)}
            except Exception:
                # 如果转换失败，直接使用字符串 _id
                query = {"_id": item_id}

            item = collection.find_one(query)
            if not item:
                raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Item not found")
            item["_id"] = str(item["_id"])  # 将 _id 转换为字符串
            return item

        @app.post(f"/{table_name}/api", status_code=status.HTTP_201_CREATED)
        async def create(item: dict):
            # 添加新数据
            collection = self.db[table_name]
            result = collection.insert_one(item)
            item["_id"] = str(result.inserted_id)  # 返回插入的 _id
            return item

        @app.put(f"/{table_name}/api/{{item_id}}")
        async def update(item_id: str, item: dict):
            # 更新数据
            collection = self.db[table_name]
            result = collection.update_one({"_id": ObjectId(item_id)}, {"$set": item})
            if result.matched_count == 0:
                raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Item not found")
            return {"message": "Data updated successfully"}

        @app.delete(f"/{table_name}/api/{{item_id}}")
        async def delete(item_id: str):
            # 删除数据
            collection = self.db[table_name]
            result = collection.delete_one({"_id": ObjectId(item_id)})
            if result.deleted_count == 0:
                raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Item not found")
            return {"message": "Data deleted successfully"}

    def _register_html_page(self, table_name: str):
        """
        注册 HTML 页面
        """
        @app.get(f"/{table_name}", response_class=HTMLResponse)
        async def view(request: Request):
            # 渲染表格页面
            table_info = self.registered_tables[table_name]
            return templates.TemplateResponse(
                "base.html",
                {
                    "request": request,
                    "title": table_info["table_alias"],  # 使用表别名
                    "system_title": self.system_title,  # 使用系统标题
                    "table_name": table_name,
                    "field_aliases": table_info["field_aliases"],  # 字段别名
                    "registered_tables": self.registered_tables,  # 注册的表信息
                },
            )

    def register_home_page(self):
        """
        注册首页路由，默认显示第一个注册的表
        """
        @app.get("/", response_class=HTMLResponse)
        async def home(request: Request):
            if not self.first_table:
                raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="No tables registered")
            # 重定向到第一个注册的表
            return templates.TemplateResponse(
                "base.html",
                {
                    "request": request,
                    "title": self.registered_tables[self.first_table]["table_alias"],
                    "system_title": self.system_title,  # 使用系统标题
                    "table_name": self.first_table,
                    "field_aliases": self.registered_tables[self.first_table]["field_aliases"],
                    "registered_tables": self.registered_tables,
                },
            )

    def run_server(self, host='0.0.0.0', port=5001):
        """
        启动 FastAPI 服务器
        """
        # 注册首页路由
        self.register_home_page()
        uvicorn.run(app, host=host, port=port)

# 示例使用
if __name__ == '__main__':
    # MongoDB 连接信息
    mongo_uri = "mongodb://senti_mind_ai:3Y3XJdpByAMmDwAe@localhost:27017/senti_mind_ai"  # 包含数据库名称

    # 创建 MongoDB 视图实例
    mongo_view = MongoDBView(mongo_uri)

    # 设置系统标题
    mongo_view.set_system_title("超级表格系统")

    # 注册 coupon 表，不指定字段别名
    mongo_view.register_table(
        table_name="coupon",
        table_alias="套餐管理",
    )

    # 注册另一个表
    mongo_view.register_table(
        table_name="new",
        table_alias="消息管理",
    )

    # 启动服务器
    mongo_view.run_server()